/*! brief A quaternion is a mathematical tool, using complex numbers to create a rotation Matrix
 *  A quaternion is divided in 2 part :  A scalar, d, and a vector : a,b,c
 *
 *  For 3D uses, the vector part represent the axis direction of a rotation, and the scalar the angle value
 */
 
 Quaternion = function(aa,bb,cc,dd)
{
	if(aa == undefined)
	{
		this.a=0;	this.b=0;	this.c=0;	this.d=1;
	}
	else
	{
		var sin_a = Math.sin(angle / 2.0);
		var cos_a = Math.cos(angle / 2.0);

		this.a 	= aa * sin_a;
		this.b 	= bb * sin_a;
		this.c 	= cc * sin_a;
		this.d 	= cos_a;

		this.Normalize();
	}
}

/************************************/
/*          Members                 */
/************************************/

    /************************************/
    /*          Methods                 */
    /************************************/

		/*! brief Return the Conjuge of the current Quaternion */
		Quaternion.prototype.Conjuge = function()
		{
			this.quat = new Quaternion();
			
				this.quat.a 	= 	-this.a;
				this.quat.b 	= 	-this.b;
				this.quat.c 	= 	-this.c;
				this.quat.d 	= 	this.d;

			return this.quat;
		}
		
		/*! brief Return the Quaternion Magnitude              */
		Quaternion.prototype.Magnitude = function()
		{
			return Math.sqrt(a*a + b*b + c*c + d*d);
		}
		
		 /*! brief  Normalize the current Quaternion   */
        Quaternion.prototype.Normalize = function()
        {
            var magnitude = this.Magnitude();

            if(magnitude>0.0)
            {
                this.a   =   this.a/magnitude;
                this.b   =   this.b/magnitude;
                this.c   =   this.c/magnitude;
                this.d   =   this.d/magnitude;
            }
        }
		
	/*! brief Return an array corresponding to a MatrixRotation from the current Quaternion */
	Quaternion.prototype.RotationMatrix = function()
	{
		var  matriceRotation = new Array[16];

		var xx      =  this.a * this.a;
		var xy      =  this.a * this.b;
		var xz      =  this.a * this.c;
		var xw      =  this.a * this.d;

		var yy      = this.b * this.b;
		var yz      = this.b * this.c;
		var yw      = this.b * this.d;

		var zz      = this.c * this.c;
		var zw      = this.c * this.d;

		matriceRotation[0]  = 1 - 2 * ( yy + zz );
		matriceRotation[1]  =     2 * ( xy - zw );
		matriceRotation[2]  =     2 * ( xz + yw );

		matriceRotation[4]  =     2 * ( xy + zw );
		matriceRotation[5]  = 1 - 2 * ( xx + zz );
		matriceRotation[6]  =     2 * ( yz - xw );

		matriceRotation[8]  =     2 * ( xz - yw );
		matriceRotation[9]  =     2 * ( yz + xw );
		matriceRotation[10] = 1 - 2 * ( xx + yy );

		matriceRotation[3]  = matriceRotation[7] = matriceRotation[11] = matriceRotation[12] = matriceRotation[13] = matriceRotation[14] = 0;
		matriceRotation[15] = 1;

		return matriceRotation;
	}

/*!	brief Multiplication of two quaternions		*/
Quaternion.prototype.MultQuat= function ( q)
{
    var qres = new Quaternion();

        qres.a = d*q.a + a*q.d + b*q.c - c*q.b;
        qres.b = d*q.b + b*q.d + c*q.a - a*q.c;
        qres.c = d*q.c + c*q.d + a*q.b - b*q.a;
        qres.d = d*q.d - a*q.a - b*q.b - c*q.c;

    return qres;
}

/************************************/
/*          Static                  */
/************************************/

	/************************************/
	/*          Members                 */
	/************************************/

		/*!	brief Create a Matrix rotation from Euler angles, avoiding Gimbal Lock		*/
		Quaternion.Euler = function (x, y, z)
		{
			var quatx 	= 	new Quaternion(1.0, 0.0, 0.0, x);
			var quaty 	=	new Quaternion(0.0, 1.0, 0.0, y);
			var quatz 	= 	new Quaternion(0.0, 0.0, 1.0, z);

			var quatxy= quatx.MultQuat(quaty);
			return quatxy.MultQuat(quatz);
		}
